package cn.yunyichina.provider.pay.wechat.service.impl;

import cn.yunyichina.provider.framework.annotation.validate.ValidateException;
import cn.yunyichina.provider.framework.annotation.validate.Validator;
import cn.yunyichina.provider.framework.common.PKGenerator;
import cn.yunyichina.provider.framework.dubbo.service.BaseService;
import cn.yunyichina.provider.framework.dubbo.service.BoneService;
import cn.yunyichina.provider.framework.dubbo.service.MessageService;
import cn.yunyichina.provider.framework.dubbo.service.PayService;
import cn.yunyichina.provider.framework.exception.CallException;
import cn.yunyichina.provider.iface.entity.ErrorCodeDefine;
import cn.yunyichina.provider.iface.entity.PersonalUserOpenid;
import cn.yunyichina.provider.iface.entity.base.PlatformExtensionUserVo;
import cn.yunyichina.provider.iface.entity.base.PlatformExtensionVo;
import cn.yunyichina.provider.iface.entity.bone.ExtensionVo;
import cn.yunyichina.provider.iface.entity.common.ResCommon;
import cn.yunyichina.provider.iface.entity.common.Response;
import cn.yunyichina.provider.iface.entity.common.ResponseObject;
import cn.yunyichina.provider.iface.entity.message.ImageTemplateListVo;
import cn.yunyichina.provider.iface.entity.message.ImageTemplateVo;
import cn.yunyichina.provider.iface.entity.message.TextTemplateVo;
import cn.yunyichina.provider.iface.entity.pay.PaymentSettingResponse;
import cn.yunyichina.provider.pay.wechat.config.Bone;
import cn.yunyichina.provider.pay.wechat.config.Message;
import cn.yunyichina.provider.pay.wechat.entity.publicMessage.Article;
import cn.yunyichina.provider.pay.wechat.entity.publicMessage.NewsMessage;
import cn.yunyichina.provider.pay.wechat.entity.publicMessage.TextMessage;
import cn.yunyichina.provider.pay.wechat.sdk.WechatConstant;
import cn.yunyichina.provider.pay.wechat.service.WechatPublicService;
import cn.yunyichina.provider.pay.wechat.utils.MessageUtil;
import cn.yunyichina.provider.pay.wechat.utils.http.HttpClient;
import cn.yunyichina.provider.pay.wechat.utils.http.HttpConstants;
import cn.yunyichina.provider.pay.wechat.utils.http.HttpResponse;
import cn.yunyichina.provider.pay.wechat.vo.PublicCreateQrcodeRequest;
import cn.yunyichina.provider.pay.wechat.vo.QrcodeRequest;
import cn.yunyichina.utils.commons.DateUtils;
import cn.yunyichina.utils.convert.JsonUtils;
import cn.yunyichina.utils.convert.XmlUtils;
import cn.yunyichina.utils.network.HttpsUtil;
import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 骨科微信公众号业务
 * Created by Joe.zhou on 2017/7/24.
 */
@Service
public class WechatPublicServiceImpl implements WechatPublicService {

    private static final Logger logger = LoggerFactory.getLogger(WechatPublicServiceImpl.class);
    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private final String GENERAL_TOKEN = "wechatCallbackToken"; //二维码扫码平台
    @Resource
    private Properties yaml;

    /**
     * 获取带参数的二维码
     * @param json
     * @interfaceName: yyt.wechatpay.wechat.public.qrcode.create
     * @return
     */
    @Override
    public ResponseObject createWechatPublicQrcode(String json) {
        logger.info("WechatPayServiceImpl.createWechatQrcode.json -> {}", json);

        ResponseObject response = new ResponseObject();

        PublicCreateQrcodeRequest request = JsonUtils.parseObject(json, PublicCreateQrcodeRequest.class);

        try {
            Validator.getInstance().validate(request);
        } catch (ValidateException ex) {
            logger.info("createWechatPublicQrcode 数据校验失败:" + ex.getMessage() + "|入参:" + json + "！");
            response.setResultCodeAndMessage("13", "数据校验失败:" + ex.getMessage() + "！");
            return response;
        }

        String appSecret = "";
        //根据appId获取密钥
        ResCommon<PaymentSettingResponse> paymentSettingResponseResCommon = PayService.getPayClient().queryPaymentSettingByAppId(request.getAppId());
        PaymentSettingResponse paymentSetting = paymentSettingResponseResCommon.getResult();
        appSecret = paymentSetting.getSecretKey();

        //构造参数
        String docInfo = request.getDoctorId() + "_"+ request.getDoctorName() + "_" + request.getAppCode() +
                "_" + request.getIntroducerId() + "_" + request.getIntroducerName() + "_" + request.getUserType()
                +"_"+request.getUserId()+"_"+request.getOrderNo()+"_"+request.getOrderType()+"_"+request.getScanType();

        String rwmJson = wechatBuildRWMJson(docInfo);

        JSONObject jsonObject = qrcodeCreate(request.getAppId(), appSecret, rwmJson);

        try {
            if(jsonObject != null){
                String ticket = jsonObject.get("ticket").toString();
                if (StringUtils.isNotBlank(ticket)) {
                    String qcodeUrl = WechatConstant.SHOW_CREATE.concat(ticket);
                    Map<String,String>map = new HashMap<>();
                    map.put("qcodeUrl" , qcodeUrl);
                    response.setResultCodeAndMessageAndResult(Response.SUCCESS_CODE ,Response.SUCCESS_MESSAGE ,map);
                }else{
                    logger.error("[createWechatQrcode] 获取ticket失败");
                    response.setResultCodeAndMessageAndResult(Response.FAILURE_CODE , Response.FAILURE_MESSAGE , "获取ticket失败");
                    return response;
                }
            }else{
                logger.info("[createWechatQrcode] 请求二维码qrcodeCreate 方法失败");
            }
        } catch (Exception e) {
            logger.error( "[WechatPublicServiceImpl.createWechatPublicQrcode 获取ticket异常 jsonObject:]" + JsonUtils.toJsonString(jsonObject), e);
        }

        return response;
    }



    /**
     * 接受微信公众号回调，统一分发
     * @param json
     * @interfaceName: yyt.wechatpay.wechat.public.callback.dispose
     * @return
     */
    @Override
    public String disposeWechatPublicCallback(String json) {

        if(XmlUtils.isXml(json)){
            logger.info("WechatPayServiceImpl.disposeWechatPublicCallback.xml -> {}", json);
            Map<String, String> map = XmlUtils.xmlToMap(json);
            String resStr="";
            // 发送方帐号（open_id）
            String fromUserName = map.get("FromUserName");
            // 公众帐号
            String toUserName = map.get("ToUserName");
            // 消息类型
            String msgType = map.get("MsgType");
            logger.info("msgType:" + msgType);
            if(msgType.equals(Message.REQ_MESSAGE_TYPE_EVENT)){        //事件推送
                String event = map.get("Event");
                String eventKey = map.get("EventKey");
                logger.info("event:" + event);
                logger.info("EventKey:" + eventKey);
                if(event.equals(Message.EVENT_TYPE_SUBSCRIBE)){
                    if(StringUtils.isNotBlank(eventKey)){
                        String[] params = eventKey.split("_");
                        if(params.length==11){
                            String doctorId = params[1];
                            String doctorName = params[2];
                            String appCode = params[3];
                            String introducerId = params[4];
                            String introducerName = params[5];
                            String userType = params[6];
                            String userId=params[7];
                            String orderNo=params[8];
                            String orderType=params[9];
                            String scanType=params[10];
                            resStr=attentionWechatPublicInfo(map , doctorId , doctorName, appCode , introducerId , introducerName ,
                                    userType , fromUserName,userId,orderNo,orderType,scanType);
                        }else if(params.length==2&&params[1].equals("liveqc")){
                            resStr=wechatLiveInfo(map);
                        }else if(params.length==2&&params[1].equals("activity")){
                            try {
                                if (yaml.getProperty(Bone.WECHAT_PAT_ID).equals(toUserName)) {
                                    resStr = doFocusedReply(fromUserName, toUserName, WechatConstant.WECHAT_TYPE, yaml.getProperty(Bone.TEXT_PAT_ACTIVITY));
                                } else if (yaml.getProperty(Bone.WECHAT_DOC_ID).equals(toUserName)) {
                                    resStr = doFocusedReply(fromUserName, toUserName, WechatConstant.WECHAT_TYPE, yaml.getProperty(Bone.TEXT_PAT_ACTIVITY));
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }else if(params.length==2&&params[1].equals("admissions")){
                            try {
                                if (yaml.getProperty(Bone.WECHAT_DOC_ID).equals(toUserName)) {
                                    resStr = doFocusedReply(fromUserName, toUserName, WechatConstant.WECHAT_TYPE, yaml.getProperty(Bone.TEXT_DOC_ADMISSIONS));
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                        return resStr;
                    }else {
                        // 关注成功自动回复
                        String result = null;
                        try {
                            if(yaml.getProperty(Bone.WECHAT_PAT_ID).equals(toUserName)){
                                result = doFocusedReply(fromUserName, toUserName,WechatConstant.WECHAT_TYPE,yaml.getProperty(Bone.TEXT_PAT_TEMPLATECODE));
                            }else if(yaml.getProperty(Bone.WECHAT_DOC_ID).equals(toUserName)){
                                result = doFocusedReply(fromUserName, toUserName,WechatConstant.WECHAT_TYPE,yaml.getProperty(Bone.TEXT_DOC_TEMPLATECODE));
                            }else {
                                logger.info("WechatPayServiceImpl.disposeWechatPublicCallback 微信原始Id不识别！toUserName：" + toUserName);
                                return "";
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        if (result != null) {
                            return result;
                        } else {
                            // 使用默认的被关注回复
                            return WechatConstant.AUTO_SUBSCRIBE;
                        }
                    }
                }else if(event.equals(Message.EVENT_TYPE_SCAN)){
                    String[] params = eventKey.split("_");
                    if(params.length==10){
                        String doctorId = params[0];
                        String doctorName = params[1];
                        String appCode = params[2];
                        String introducerId = params[3];
                        String introducerName = params[4];
                        String userType = params[5];
                        String userId=params[6];
                        String orderNo=params[7];
                        String orderType=params[8];
                        String scanType=params[9];
                        resStr= attentionWechatPublicInfo(map ,doctorId , doctorName , appCode , introducerId , introducerName ,
                                userType , fromUserName,userId,orderNo,orderType,scanType);
                    }else if(params.length==1&&params[0].equals("liveqc")){
                        resStr=wechatLiveInfo(map);
                    }else if(params.length==1&&params[0].equals("activity")){
                        try {
                            if (yaml.getProperty(Bone.WECHAT_PAT_ID).equals(toUserName)) {
                                resStr = doFocusedReply(fromUserName, toUserName, WechatConstant.WECHAT_TYPE, yaml.getProperty(Bone.TEXT_PAT_ACTIVITY));
                            } else if (yaml.getProperty(Bone.WECHAT_DOC_ID).equals(toUserName)) {
                                resStr = doFocusedReply(fromUserName, toUserName, WechatConstant.WECHAT_TYPE, yaml.getProperty(Bone.TEXT_PAT_ACTIVITY));
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }else if(params.length==1&&params[0].equals("admissions")){
                        try {
                            if (yaml.getProperty(Bone.WECHAT_DOC_ID).equals(toUserName)) {
                                resStr = doFocusedReply(fromUserName, toUserName, WechatConstant.WECHAT_TYPE, yaml.getProperty(Bone.TEXT_DOC_ADMISSIONS));
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    return resStr;
                }else{
                    logger.info("WechatPayServiceImpl.disposeWechatPublicCallback 消息类型识别失败！event：" + event);
                    return "";
                }

            }else{
                logger.info("WechatPayServiceImpl.disposeWechatPublicCallback 类型识别失败！msgType：" + msgType);
                return "";
            }
        }else{
            logger.info("WechatPayServiceImpl.disposeWechatPublicCallback.json -> {}", json);
            return checkWechatPublicUrl(json);
        }
    }

    /**
     * 被关注回复
     *
     * @param fromUserName
     * @param toUserName
     * */
    public String doFocusedReply(String fromUserName, String toUserName,Short platformType,String templateCode)
            throws Exception {
        TextTemplateVo textTemp=new TextTemplateVo();
        textTemp.setPlatformType(platformType);
        textTemp.setTemplateCode(templateCode);
        logger.info("查询文本消息模板入参:request->textTemp:{}", JSON.toJSONString(textTemp));
        Response response = MessageService.callHumpFromInternal("yyt.message.msg.text.template.get", JsonUtils.toJsonString(textTemp));
        logger.info("查询文本消息模板出参:reponse->response:{}" + JSON.toJSONString(response));
        if("0".equals(response.getResultCode())){
            textTemp = JsonUtils.parseObject(response.getResult(), TextTemplateVo.class);
            if (textTemp != null) {
                    // 回复文本
                    return sendText(fromUserName, toUserName, textTemp.getMsgContent());
            }
        }
        return null;
    }

    /**
     * 回复文本
     *
     * @param fromUserName
     * @param toUserName
     * @param content
     * 文本内容
     */
    private String sendText(String fromUserName, String toUserName, String content) {
        TextMessage textMessage = new TextMessage();
        textMessage.setToUserName(fromUserName);
        textMessage.setFromUserName(toUserName);
        textMessage.setCreateTime(System.currentTimeMillis());
        textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);
        textMessage.setContent(content);
        return MessageUtil.textMessageToXml(textMessage);
    }

    /**
     * 获取用户关注后返回信息
     * @interfaceName: yyt.pay.wechat.publie.info.attention
     * @return
     */
    public String attentionWechatPublicInfo(Map<String, String> map , String doctorId, String doctorName , String appCode, String introducerId, String introducerName,
                                            String userType , String openId,String userId,String orderNo,String orderType,String scanType) {
        logger.info("WechatPayServiceImpl.attentionWechatPublicInfo.json -> {}", JSONUtils.toJSONString(map));
        logger.info("doctorId:"+doctorId+",doctorName:"+doctorName+",appCode:"+appCode+",introducerId:"+introducerId+",introducerName:"
                +introducerName+",userType:"+userType+",openId:"+openId+",userId:"+userId+",orderNo:"+
                orderNo+",orderType:"+orderType+",scanType:"+scanType);

        if(scanType!=null&&("1".equals(scanType)||"2".equals(scanType))){
            //记录患者关系
            checkInputPersonalUser(openId,doctorId,doctorName,appCode,userId);
        }
        String resultStr = "";

        //处理用户关注后的图文消息推送逻辑
        if(StringUtils.isNotBlank(doctorName)){

            try {
                //根据模板code查询图片信息
                ImageTemplateVo imageTemplateVo = new ImageTemplateVo();
                imageTemplateVo.setTemplateCode(yaml.getProperty(Bone.MAIN_TEMPLATECODE));

                Response response = BaseService.callHumpFromInternal("yyt.base.image.template.by.code.get", JsonUtils.toJsonString(imageTemplateVo));

                logger.info("获取骨科链接模板 yyt.base.image.template.by.code.get -->" + JsonUtils.toJsonString(response));
                if("0".equals(response.getResultCode())){
                    List<ImageTemplateListVo> images = JsonUtils.parseArray(response.getResult(), ImageTemplateListVo.class);
                    ImageTemplateListVo imageTemplate = null;
                    String rule = "";
                    if("1".equals(userType)){
                        rule = yaml.getProperty(Bone.DOC_TEMPLATECODE);
                    }else{
                        rule = yaml.getProperty(Bone.PER_TEMPLATECODE);
                    }
                    if("1".equals(scanType)){
                        rule=yaml.getProperty(Bone.BIND_DOC_PAT);
                    }
                    for (ImageTemplateListVo image : images) {
                        if(rule.equals(image.getImageTemplateCode())){
                            imageTemplate = image;
                            break;
                        }
                    }
                    logger.info("要发送的图文消息模板:"+JSON.toJSONString(imageTemplate));
                    //根据用户类型组装点击链接和title
                    String actionUrl = "";
                    String title = "";
                    if("1".equals(userType)){
                        actionUrl = imageTemplate.getActionUrl() + "app_code="+ appCode + "&introducer_id=" + introducerId + "&introducer_name=" + introducerName;
                        title = "我是" + doctorName + "，邀请您入驻仁医骨科平台，立即点击前往签约";
                    }else{
                        if("1".equals(scanType)){
                            title="我是" + doctorName + "，感谢关注仁医骨德大众版，点击立即注册登录即可预约咨询医生";
                            actionUrl=imageTemplate.getActionUrl()+appCode;
                        }else {
                            JSONObject jsonObject =new JSONObject();
                            String orderTtpeStr=null;
                            if("91".equals(orderType)){
                                orderTtpeStr="问诊订单";
                                jsonObject.put("url","dist/#/user/consultation/step2");
                            }else if("92".equals(orderType)||"93".equals(orderType)){
                                orderTtpeStr="手术预约订单";
                                jsonObject.put("url","dist/#/user/reservation/step2");
                            }else {
                                logger.info("暂时不支持此订单类型："+orderType);
                                return "";
                            }
                            jsonObject.put("app_code",appCode);
                            jsonObject.put("user_id",userId);
                            jsonObject.put("order_type",orderType);
                            jsonObject.put("order_no",orderNo);
                            logger.info("要转化的url及参数模板："+JSON.toJSONString(jsonObject));
                            actionUrl= MessageUtil.parseUrl(imageTemplate.getActionUrl(),jsonObject);
                            title = "我是" + doctorName + "医生，已为您提交了"+orderTtpeStr+"，请立即注册登录仁医骨科平台查看并支付";
                        }
                    }
                    if(imageTemplate != null){
                        logger.info("PicUrl:" + imageTemplate.getImageUrl());
                        logger.info("Url:" + actionUrl);
                        List<Article> articles = new ArrayList<Article>();
                        Article article = new Article();
                        article.setTitle(title);
                        article.setPicUrl(imageTemplate.getImageUrl());
                        article.setUrl(actionUrl);    //点击跳转链接
                        articles.add(article);

                        NewsMessage newsResp = new NewsMessage();
                        newsResp.setCreateTime(System.currentTimeMillis());
                        newsResp.setFromUserName(map.get("ToUserName"));
                        newsResp.setToUserName(map.get("FromUserName"));
                        newsResp.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_NEWS);
                        newsResp.setArticleCount(articles.size());
                        newsResp.setArticles(articles);
                        resultStr = MessageUtil.newsMessageToXml(newsResp);
                    }else{
                        logger.info("无法获取图片"+ rule +"模板配置参数.. templateCode：" + imageTemplateVo.getTemplateCode());
                    }

                }else{
                    logger.info("无法获取图片模板配置参数.. templateCode：" + imageTemplateVo.getTemplateCode());
                    return "";
                }
            } catch (Exception e) {
                logger.error("[WechatPublicServiceImpl.attentionWechatPublicInfo 获取用户关注后返回信息异常]" , e);
            }

        }else{
            logger.info("获取医生失败.. doctorId：" + doctorId);
            return "";
        }

        logger.info("[attentionWechatPublicInfo  resultStr -->]" + resultStr);

        return resultStr;
    }

    /**
     * 获取用户关注后返回信息(患者扫码推送mayer教授直播图文)
     *
     */
    public String wechatLiveInfo(Map<String, String> map) {
        logger.info("[WechatPayServiceImpl.wechatLiveInfo.json -> wechat map request] {}", JSONUtils.toJSONString(map));
        String resultStr = "";
        try {
            List<Article> articles = new ArrayList<Article>();
            Article article = new Article();
            article.setTitle(yaml.getProperty(Bone.LVIE_TITLE));
            article.setPicUrl(yaml.getProperty(Bone.PIC_LIVE_URL));
            article.setUrl(yaml.getProperty(Bone.CLICK_LIVE_URL));    //点击跳转链接
            articles.add(article);
            NewsMessage newsResp = new NewsMessage();
            newsResp.setCreateTime(System.currentTimeMillis());
            newsResp.setFromUserName(map.get("ToUserName"));
            newsResp.setToUserName(map.get("FromUserName"));
            newsResp.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_NEWS);
            newsResp.setArticleCount(articles.size());
            newsResp.setArticles(articles);
            resultStr = MessageUtil.newsMessageToXml(newsResp);
        } catch (Exception e) {
            logger.error("[WechatPublicServiceImpl.wechatLiveInfo 获取用户关注后返回信息(患者扫码推送mayer教授直播图文)]", e);
        }
        logger.info("[WechatPublicServiceImpl.wechatLiveInfo  responseStr -->]" + resultStr);
        return resultStr;
    }


    /**
     * 记录患者与医生关系
     * @param openId
     */
    public void checkInputPersonalUser(String openId , String doctorId , String doctorName ,String appCode,String userId){
        logger.info("记录患者与医生关系 openId:" + openId + " , doctorId:" + doctorId +", appCode:" + appCode+",userId："+userId);
        try {
            if(StringUtils.isNotBlank(openId)){
                Map<String,Object> param = new HashMap<String,Object>();
                ExtensionVo extensionVo = new ExtensionVo();
                String perUserid=null;
                String patAppId=yaml.getProperty(Bone.WECHAT_PAT_APP_ID);
                logger.info("扫码绑定医患关系->获取患者openId对应的userId->request:appId=" + patAppId + ",opendId=" + openId);
                PersonalUserOpenid personalUser = BaseService.getBaseClient().getPersonalUserOpenid(null,patAppId,openId);
                logger.info("扫码绑定医患关系->获取患者openId对应的userId->response:" + JsonUtils.toJsonString(personalUser));
                if (personalUser != null) {
                    perUserid=personalUser.getPerUserId();
                }
                param.put("personal_open_id" , openId);
                param.put("org_app_code" , appCode);
                param.put("org_user_id" , doctorId);
                param.put("personal_user_id",perUserid);
                param.put("pay_mode" , 1);
                param.put("type","3");//区分是内部调用还是外部（扫码）
                Response response = BoneService.callHumpFromInternal("yyt.bone.bone.extension.get", JsonUtils.toJsonString(param));
                if("-1".equals(response.getResultCode())){
                    //新增
                    extensionVo.setId(PKGenerator.generateId());
                    extensionVo.setPersonalOpenId(openId);
                    extensionVo.setPersonalUserId(perUserid);
                    extensionVo.setOrgAppCode(appCode);
                    extensionVo.setOrgUserId(doctorId);
                    extensionVo.setOrgUserName(doctorName);
                    extensionVo.setPayMode((short) 1);
                    extensionVo.setDefaultFlag((short) 1);
                    extensionVo.setCreatedTime(simpleDateFormat.format(new Date()));
                    extensionVo.setUpdateTime(simpleDateFormat.format(new Date()));
                    List<ExtensionVo> voList=new ArrayList<>();
                    voList.add(extensionVo);
                    BoneService.callHumpFromInternal("yyt.bone.bone.extension.add", JsonUtils.toJsonString(voList));

                }else{
                    logger.info("[checkInputPersonalUser 记录患者与医生关系] 该医生已存在 json -->：" + JsonUtils.toJsonString(response.getResult()));
                    if(userId!=null&&!"null".equals(userId)){//医生帮患者预约手术
                        List<ExtensionVo> voList = JsonUtils.parseArray(response.getResult(), ExtensionVo.class);
                        for (ExtensionVo vo : voList) {
                            vo.setPersonalUserId(userId);
                            vo.setUpdateTime(simpleDateFormat.format(new Date()));
                            BoneService.callHumpFromInternal("yyt.bone.bone.extension.update", JsonUtils.toJsonString(vo));
                        }
                    }
                }
            }else{
                logger.info("checkInputPersonalUser openId is null..");
            }
        } catch (Exception e) {
            logger.error("[WechatPublicServiceImpl.checkInputPersonalUser 记录患者与医生关系异常]" , e);
        }
    }


    /**
     * 网址接入-确认请求来自微信服务器
     */
    public String checkWechatPublicUrl(String json) {
        logger.info("WechatPayServiceImpl.checkWechatPublicUrl.json -> {}", json);

        JSONObject param = JSONObject.parseObject(json);

        // 微信加密签名
        String signature = (String) param.get("signature");
        // 时间戳
        String timestamp = (String) param.get("timestamp");
        // 随机数
        String nonce = (String) param.get("nonce");
        // 随机字符串
        String echostr = (String) param.get("echostr");

        logger.info("获取到解析完毕参数:signature:" + signature +",timestamp:"+timestamp+",nonce:"+nonce+",echostr:" + echostr);

        try {
            String[] strSet = new String[] { WechatConstant.WECHAT_TOKEN, timestamp, nonce };
            java.util.Arrays.sort(strSet);
            String total = "";
            for (String string : strSet){
                total = total + string;
            }
            // SHA-1加密实例
            MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
            sha1.update(total.getBytes());
            byte[] codedBytes = sha1.digest();
            String codedString = new BigInteger(1, codedBytes).toString(16);// 将加密后的字节数组转换成字符串。
            if (codedString.equals(signature)){ // 将加密的结果与请求参数中的signature比对，如果相同，原样返回echostr参数内容
                logger.info("WechatPayServiceImpl.checkWechatPublicUrl -> Success! echostr:" + echostr);
                return echostr;
            }else{
                logger.info("校验失败 codedString:" + codedString + "====== signature:" + signature);
            }
        } catch (NoSuchAlgorithmException e) {
            logger.error("WechatPayServiceImpl.checkWechatPublicUrl -> Fail! echostr:" + echostr , e);
        }

        return null;
    }




    /**
     * 构建微信二维码请求json
     * ps:临时二维码最大时间为 2592000秒 即 30天
     * @param docStr
     * @return
     */
    private static String wechatBuildRWMJson(String docStr) {
        JSONObject result = new JSONObject();
        JSONObject codeInfo = new JSONObject();
        JSONObject scene = new JSONObject();
        scene.put("scene_id", PKGenerator.generateId());
        scene.put("scene_str", docStr);
        codeInfo.put("scene", scene);
        result.put("action_info", codeInfo);
        result.put("expire_seconds", 2592000); // 30天
        result.put("action_name", "QR_STR_SCENE");  //QR_STR_SCENE 为临时的字符串参数值
        return result.toString();
    }


    /**
     * 请求获取二维码
     * @param appId
     * @param appSecret
     * @param qcJson
     * @return
     */
    public static JSONObject qrcodeCreate(String appId, String appSecret, String qcJson) {
        logger.info("qrcodeCreate , 入参 appId: " + appId +" - " + appSecret + " - " + qcJson);
        String tocken = getAccessToken(appId , appSecret);
        String postURL = WechatConstant.QRCODE_CREATE + tocken;
        HttpResponse response = new HttpClient().post(postURL, qcJson, HttpConstants.JSON_TYPE, HttpConstants.CHARACTER_ENCODING_UTF8);
        if (response.getStatusCode() == 200) {
            return response.asJSONObject();
        } else {
            logger.info(JsonUtils.toJsonString(response));
            return null;
        }
    }



    /**
     * 实时获取AccessToken 日上限数2000
     * @param appId
     * @param appSecret
     * @return
     */
    public static String getAccessToken(String appId, String appSecret) {
        logger.info("getAccessToken:appId="+appId+",appSecret="+appSecret);

        String url =  WechatConstant.ACCESS_TOKEN_URL + "&appid=" + appId + "&secret=" + appSecret;
        String accessToken = "";
        try {
            String strJsonReturn = HttpsUtil.doSslGet(url, "UTF-8");
            JSONObject response = JsonUtils.parseObject(strJsonReturn);
            if (response.containsKey("errcode")) {// 失败
                logger.error("获取ccess_token失败:" + strJsonReturn);
                throw new CallException(ErrorCodeDefine.MESSAGE_ACCESS_TOKEN,"获取新access_token失败:" + strJsonReturn);
            } else {// 成功
                logger.info("获取access_token成功:" + strJsonReturn);
                accessToken = response.getString("access_token");
            }
        } catch (Exception e) {
            logger.error("获取新access_token失败" , e);
        }

        return accessToken;
    }


    //=============================以下为管理平台通用===================================//



    /**
     * 获取带参数的二维码(通用)
     * @param json
     * @interfaceName: yyt.wechatpay.wechat.public.qrcode.general.create
     * @return
     */

    public ResponseObject createWechatPublicQrcodeGeneral(String json) {
        logger.info("WechatPayServiceImpl.createWechatQrcode.json -> {}", json);

        ResponseObject response = new ResponseObject();

        QrcodeRequest request = JsonUtils.parseObject(json, QrcodeRequest.class);
        if(request.getCodeType() == 0){
            request.setSeconds(null);
        }

        try {
            Validator.getInstance().validate(request);
        } catch (ValidateException ex) {
            logger.info("createWechatPublicQrcodeGeneral 数据校验失败:" + ex.getMessage() + "|入参:" + json + "！");
            response.setResultCodeAndMessage("13", "数据校验失败:" + ex.getMessage() + "！");
            return response;
        }

        String appSecret = "";
        //根据appId获取密钥
        ResCommon<PaymentSettingResponse> paymentSettingResponseResCommon = PayService.getPayClient().queryPaymentSettingByAppId(request.getAppId());
        PaymentSettingResponse paymentSetting = paymentSettingResponseResCommon.getResult();
        appSecret = paymentSetting.getSecretKey();

        String docInfo = "";
        //构造参数
        if(request.getCodeType() == 0){
            docInfo = request.getExtension_id();
        }else{
            docInfo = json;
        }

        String rwmJson = wechatBuildRWMJson(docInfo ,request.getCodeType() , request.getSeconds());

        JSONObject jsonObject = qrcodeCreate(request.getAppId(), appSecret, rwmJson);

        try {
            if(jsonObject != null){
                String ticket = jsonObject.get("ticket").toString();
                if (StringUtils.isNotBlank(ticket)) {
                    String qcodeUrl = WechatConstant.SHOW_CREATE.concat(ticket);
                    response.setResultCodeAndMessageAndResult(Response.SUCCESS_CODE ,Response.SUCCESS_MESSAGE ,qcodeUrl);
                }else{
                    logger.error("[createWechatPublicQrcodeGeneral] 获取ticket失败");
                    response.setResultCodeAndMessageAndResult(Response.FAILURE_CODE , Response.FAILURE_MESSAGE , "获取ticket失败");
                    return response;
                }
            }else{
                logger.info("[createWechatPublicQrcodeGeneral] 请求二维码qrcodeCreate 方法失败");
            }
        } catch (Exception e) {
            logger.error( "[WechatPublicServiceImpl.createWechatPublicQrcodeGeneral 获取ticket异常 jsonObject:]" + JsonUtils.toJsonString(jsonObject), e);
            response.setResultCodeAndMessage(Response.FAILURE_CODE , "获取ticket异常 jsonObject:" + JsonUtils.toJsonString(jsonObject));
        }

        return response;
    }





    /**
     * 接受微信公众号回调，统一分发(通用)
     * @param json
     * @interfaceName: yyt.wechatpay.wechat.public.callback.get
     * @return
     */
    public String getWechatPublicCallback(String json) {

        if(XmlUtils.isXml(json)){
            logger.info("WechatPayServiceImpl.getWechatPublicCallback.xml -> {}", json);
            Map<String, String> map = XmlUtils.xmlToMap(json);
            // 用户（open_id）
            String fromUserName = map.get("FromUserName");
            // 公众帐号
            String toUserName = map.get("ToUserName");
            // 消息类型
            String msgType = map.get("MsgType");
            logger.info("msgType:" + msgType);
            if(msgType.equals(Message.REQ_MESSAGE_TYPE_EVENT)){  //事件推送
                String event = map.get("Event");
                String eventKey = map.get("EventKey");
                logger.info("event:" + event);
                logger.info("EventKey:" + eventKey);
                if(StringUtils.isNotBlank(eventKey)){
                    if(event.equals(Message.EVENT_TYPE_SUBSCRIBE)){  //关注订阅事件
                        String datas = eventKey.substring(eventKey.indexOf("_") + 1, eventKey.length());
                        logger.info("最终获得微信扫码回调 json：" + datas);

                        //由于微信永久二维码传参不支持多参数json
                        QrcodeRequest qrcodeRequest = null;
                        if(datas.contains("extension_id")){
                            qrcodeRequest = JsonUtils.parseObject(datas, QrcodeRequest.class);
                        }else{
                            qrcodeRequest = new QrcodeRequest();
                            qrcodeRequest.setExtension_id(datas);
                        }
                        qrcodeRequest.setUserOpenId(fromUserName);

                        return saveScaner(qrcodeRequest);
                    }else if(event.equals(Message.EVENT_TYPE_SCAN)){  //扫码事件
                        logger.info("事件类型：扫码事件");
                    }else{
                        logger.info("WechatPayServiceImpl.disposeWechatPublicCallback 消息类型识别失败！event：" + event);
                    }
                }else{
                    logger.info("WechatPayServiceImpl.getWechatPublicCallback 获取EventKey参数为空！");
                }

            }else{
                logger.info("WechatPayServiceImpl.disposeWechatPublicCallback 类型识别失败！msgType：" + msgType);
            }
        }else{
            logger.info("WechatPayServiceImpl.disposeWechatPublicCallback.json -> {}", json);
            return checkWechatPublicUrlGeneral(json);
        }

        return "1";
    }


    /**
     * 确认请求来自微信服务器(通用)
     */
    public String checkWechatPublicUrlGeneral(String json) {
        logger.info("WechatPayServiceImpl.checkWechatPublicUrlGeneral.json -> {}", json);

        JSONObject param = JSONObject.parseObject(json);

        // 微信加密签名
        String signature = (String) param.get("signature");
        // 时间戳
        String timestamp = (String) param.get("timestamp");
        // 随机数
        String nonce = (String) param.get("nonce");
        // 随机字符串
        String echostr = (String) param.get("echostr");

        logger.info("获取到解析完毕参数:signature:" + signature +",timestamp:"+timestamp+",nonce:"+nonce+",echostr:" + echostr);

        try {
            String[] strSet = new String[] { GENERAL_TOKEN, timestamp, nonce };
            Arrays.sort(strSet);
            String total = "";
            for (String string : strSet){
                total = total + string;
            }
            // SHA-1加密实例
            MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
            sha1.update(total.getBytes());
            byte[] codedBytes = sha1.digest();
            String codedString = new BigInteger(1, codedBytes).toString(16);// 将加密后的字节数组转换成字符串。
            if (codedString.equals(signature)){ // 将加密的结果与请求参数中的signature比对，如果相同，原样返回echostr参数内容
                logger.info("WechatPayServiceImpl.checkWechatPublicUrlGeneral -> Success! echostr:" + echostr);
                return echostr;
            }else{
                logger.info("校验失败 codedString:" + codedString + "====== signature:" + signature);
            }
        } catch (NoSuchAlgorithmException e) {
            logger.error("WechatPayServiceImpl.checkWechatPublicUrlGeneral -> Fail! echostr:" + echostr , e);
        }

        return null;
    }



    /**
     * 构建微信二维码请求json
     * ps:临时二维码最大时间为 2592000 秒 即 30天
     * @param docStr
     * @param codeType  0:永久 1：临时
     * @return
     */
    private static String wechatBuildRWMJson(String docStr , Integer codeType , Integer seconds) {
        JSONObject result = new JSONObject();
        JSONObject codeInfo = new JSONObject();
        JSONObject scene = new JSONObject();
        if(codeType != 0){
            scene.put("scene_id", PKGenerator.generateId());
        }
        scene.put("scene_str", docStr);
        codeInfo.put("scene", scene);
        result.put("action_info", codeInfo);
        if(codeType == 0){
            result.put("action_name", "QR_LIMIT_STR_SCENE");  //QR_LIMIT_SCENE 为永久的字符串参数值
        }else{
            result.put("expire_seconds", seconds);
            result.put("action_name", "QR_STR_SCENE");  //QR_STR_SCENE 为临时的字符串参数值
        }
        return result.toString();
    }


    /**
     * 保存扫码关注信息
     * @param request
     */
    public String saveScaner(QrcodeRequest request){
        logger.info("WechatPayServiceImpl.saveScaner.json -> {}", JsonUtils.toJsonString(request));
        Response response = new Response();
        //根据继承id查询二维码表关注信息
        Map<String,String > map =new HashMap<String ,String >();
        map.put("id" , request.getExtension_id());

        //查询推广人信息
        Response scanerResponse = BaseService.callHumpFromInternal("yyt.base.scaner.platform.info.select", JsonUtils.toJsonString(map));
        if("0".equals(scanerResponse.getResultCode())){
            List<PlatformExtensionVo> extensionVos = JsonUtils.parseArray(scanerResponse.getResult(), PlatformExtensionVo.class);
            PlatformExtensionVo extensionVo = extensionVos.get(0);

            PlatformExtensionUserVo extensionUserVo = new PlatformExtensionUserVo();
            extensionUserVo.setId(PKGenerator.generateId());
            extensionUserVo.setPersonalOpenId(request.getUserOpenId());
            extensionUserVo.setOrgUserOpenId(extensionVo.getOrgUserOpenId());
            extensionUserVo.setOrgUserId(extensionVo.getOrgUserId());
            extensionUserVo.setOrgUserName(extensionVo.getOrgUserName());
            extensionUserVo.setPlatformExtensionId(extensionVo.getId());
            extensionUserVo.setCreatedTime(DateUtils.getDateTimeStr());
            extensionUserVo.setUpdateTime(DateUtils.getDateTimeStr());
            response = BaseService.callHumpFromInternal("yyt.base.scaner.platform.user.add", JsonUtils.toJsonString(extensionUserVo));
            if("0".equals(response.getResultCode())){
                logger.info("保存扫码关注信息成功 extensionUserVo：" + JsonUtils.toJsonString(extensionUserVo));
            }
        }

        return  response.getResultMessage();
    }


}
